package edu.whu.tao.service.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;

import com.xiaoleilu.hutool.lang.Validator;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;
import com.xiaoleilu.hutool.util.CollectionUtil;
import com.xiaoleilu.hutool.util.StrUtil;

import edu.whu.tao.constant.CommonConstants;
import edu.whu.tao.dao.GenericDao;
import edu.whu.tao.exception.BaseException;
import edu.whu.tao.service.GenericService;
import edu.whu.tao.util.BaseObject;
import edu.whu.tao.util.CommonResult;
import edu.whu.tao.util.PageData;
import edu.whu.tao.util.PageParamCommand;
import edu.whu.tao.util.ReflectionUtils;

public abstract class AbstractGenericServiceImpl<T extends BaseObject> implements GenericService<T> {

	private final static Log log = LogFactory.get();
	
	public abstract GenericDao<T> getDao();

	/**
	 * 
	 * <p>id属性</p>
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public abstract Serializable getIdProperty();

	/**
	 * 
	 * <p>是否删除状态</p>
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public abstract Serializable getStateProperty();

	public abstract Class<T> getClazz();
	
	/**
	 * 
	 * <p>判断某数据是否被引用</p>
	 * @param id
	 * @return
	 * @author 陶焕(13294175866)
	 */
	protected boolean isCited(Serializable id){
		
		return false;
	}
	
	/**
	 * 
	 * <p>添加和编辑前的校验</p>
	 * @param entity
	 * @param isInsert
	 * @return
	 * @throws Exception
	 * @author 陶焕(13294175866)
	 */
	protected CommonResult<T> check(T entity,boolean isInsert) throws Exception {
		CommonResult<T> result = new CommonResult<T>(CommonResult.successCode);
		
		return result;
	}

	@Override
	public CommonResult<T> get(Serializable id)  throws Exception {
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		T data = getDao().getByKey(getClazz(), id);
		result.setData(data);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<T> getById(Serializable id)  throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		T data = getDao().getById(getClazz(), id, getIdProperty(), getStateProperty());
		result.setData(data);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<T> getOneByCri(DetachedCriteria detachedCriteria)  throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		CommonResult<T> datas = findByCriteria(detachedCriteria);
		List<T> list = datas.getDatas();
		if ((list != null) && (!list.isEmpty())) {
			T data = (T) list.get(0);
			result.setData(data);
			result.setSuccess(CommonResult.successCode);
			return result;
		}
		return result;
	}

	@Override
	public CommonResult<T> update(T entity) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		check(entity,false);
		CommonResult<T> tmp = get(entity.getId());
		T updateEntity = tmp.getData();
		ReflectionUtils.copyProperties(entity, updateEntity);
		getDao().update(updateEntity);
		result.setData(updateEntity);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<T> save(T entity) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		check(entity,true);
		getDao().save(entity);
		result.setData(entity);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Integer> deleteHard(T entity) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		if(isCited(entity.getId())){
			result.setMessage(CommonConstants.DELETE_CANCEL_BY_CITE);
			return result;
		}
		getDao().delete(entity);
		result.setData(1);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Integer> deleteHardByKey(Serializable id) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		if(isCited(id)){
			result.setMessage(CommonConstants.DELETE_CANCEL_BY_CITE);
			return result;
		}
		int data = getDao().deleteByKey(getClazz(), id, getIdProperty());
		result.setData(data);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Integer> deleteHardByKeys(Serializable[] ids) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		List<Serializable> canDeleteIds = new ArrayList<Serializable>();
		int totalSize = ids.length;
		for (int i = 0; i < ids.length; i++) {
			Serializable id = ids[i];
			//如果被引用了，就不能删除
			if(isCited(id)){
				continue;
			}
			canDeleteIds.add(id);
		}
		int nowSize = canDeleteIds.size();
		if(nowSize != totalSize){
			String message = StrUtil.format(CommonConstants.DELETE_NOT_ALL_MSG_TPL, totalSize,nowSize,totalSize - nowSize);
			result.setMessage(message);
		}
		if(nowSize != 0){
			int count = getDao().deleteByKeys(getClazz(), canDeleteIds.toArray(new Serializable[0]), getIdProperty());
			result.setData(count);
		}
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Integer> deleteSoftByKey(Serializable id) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		if(isCited(id)){
			result.setMessage(CommonConstants.DELETE_CANCEL_BY_CITE);
			return result;
		}
		int data = getDao().deleteSoftByKey(getClazz(), id, getIdProperty(), getStateProperty());
		result.setData(data);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Integer> deleteSoftByKeys(Serializable[] ids) throws Exception{
		// TODO Auto-generated method stub
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		List<Serializable> canDeleteIds = new ArrayList<Serializable>();
		int totalSize = ids.length;
		for (int i = 0; i < ids.length; i++) {
			Serializable id = ids[i];
			//如果被引用了，就不能删除
			if(isCited(id)){
				continue;
			}
			canDeleteIds.add(id);
		}
		int nowSize = canDeleteIds.size();
		if(nowSize != totalSize){
			String message = StrUtil.format(CommonConstants.DELETE_NOT_ALL_MSG_TPL, totalSize,nowSize,totalSize - nowSize);
			result.setMessage(message);
		}
		if(nowSize != 0){
			int count = getDao().deleteSoftByKeys(getClazz(), canDeleteIds.toArray(new Serializable[0]), getIdProperty(), getStateProperty());
			result.setData(count);
		}
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Long> count(DetachedCriteria detachedCriteria) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<Long> result = new CommonResult<Long>(CommonResult.failureCode);
		long data = getDao().count(detachedCriteria);
		result.setData(data);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Integer> saveOrUpdateAll(List<T> entities) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		if(CollectionUtil.isNotEmpty(entities)){
			getDao().saveOrUpdateAll(entities);
			result.setData(entities.size());
		}
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<T> findByCriteria(DetachedCriteria detachedCriteria) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		List<T> datas = getDao().findByCriteria(getClazz(), detachedCriteria);
		result.setDatas(datas);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<T> findByCriteria(DetachedCriteria detachedCriteria, int page, int row) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		List<T> datas = getDao().findByCriteria(getClazz(), detachedCriteria, page, row);
		result.setDatas(datas);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public PageData<T> getByPage(DetachedCriteria detachedCriteria, int page, int row) throws Exception {
		// TODO Auto-generated method stub
		PageData<T> pageData = new PageData<T>();
		pageData.setPage(page);
		pageData.setPageSize(row);
		long count = getDao().count(detachedCriteria);
		pageData.setTotal(count);
		List<T> datas = getDao().findByCriteria(getClazz(), detachedCriteria, page, row);
		pageData.setRows(datas);
		return pageData;
	}
	
	@Override
	public CommonResult<T> sqlQuery(String querySql, Object... params) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		List<T> datas = getDao().sqlQuery(getClazz(), querySql, params);
		result.setDatas(datas);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<T> sqlQuery(String querySql, Object[] params, int page, int row) throws Exception {
		// TODO Auto-generated method stub
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		List<T> datas = getDao().sqlQuery(getClazz(), querySql, params, page, row);
		result.setDatas(datas);
		result.setSuccess(CommonResult.successCode);
		return result;
	}
	
	
	/**
	 * 
	 * <p>非空校验</p>
	 * @param field
	 * @param errorMsg
	 * @return
	 * @author 陶焕(13294175866)
	 * @throws BaseException 
	 */
	public CommonResult<T> checkEmptyField(Object field,String errorMsg) throws BaseException{
		log.info("AbstractGenericServiceImpl.checkEmptyField请求参数:{},{}", field,errorMsg);
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		/**
		 * 非空校验
		 */
		if(Validator.isEmpty(field)){
			result.setMessage(errorMsg);
			throw new BaseException(errorMsg);
			//return result;
		}
		//成功
		result.setSuccess(CommonResult.successCode);
		log.info("AbstractGenericServiceImpl.checkEmptyField返回参数:{}", result);
		return result;
	}
	
	/**
	 * 
	 * <p>校验字段是否唯一</p>
	 * @param model
	 * @param isInsert
	 * @return
	 * @author 陶焕(13294175866)
	 * @throws Exception 
	 */
	public CommonResult<T> checkUniqueField(boolean isInsert,String id,String errorMsg,String[] fieldNames,
			Object[] fieldValue) throws Exception{
		log.info("AbstractGenericServiceImpl.checkUniqueField请求参数:{},{},{},{}", isInsert,id,errorMsg,fieldNames,fieldValue);
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		/**
		 * 唯一校验
		 */
		//Map<String, Object> condition = new HashMap<String, Object>();
		DetachedCriteria condition = DetachedCriteria.forClass(getClazz());
		if(fieldNames != null && fieldNames.length > 0){
			for(int i=0; i < fieldNames.length; i++){
				//condition.put(fieldNames[i], fieldValue[i]);
				condition.add(Restrictions.eq(fieldNames[i], fieldValue[i]));
			}
		}else {
			//不需要唯一校验
			result.setSuccess(CommonResult.successCode);
			return result;
		}
		
		CommonResult<T> page = findByCriteria(condition);
		List<T> datas = page.getDatas();
		int size = datas.size();
		if(isInsert){//插入
			if(size > 0){//当存在相同的名称时
				result.setMessage(errorMsg);
				return result;
			}
		} else {//更新
			if(size > 1){
				result.setMessage(errorMsg);
				return result;
			} else if (size == 1) {
				BaseObject tmp = datas.get(0);
				//存在一个时,如果不是当前更新的这条数据,那么就失败
				if(!StringUtils.equals(String.valueOf(tmp.getId()), id)){
					result.setMessage(errorMsg);
					throw new BaseException(errorMsg);
					//return result;
				}
			} else {
				
			}
			
		}
		//确定是唯一
		result.setSuccess(CommonResult.successCode);
		log.info("AbstractGenericServiceImpl.checkUniqueField返回参数:{}", result);
		return result;
	}
	
	/**
	 * 
	 * <p>非空校验(批量)</p>
	 * @param field
	 * @param errorMsg
	 * @return
	 * @author 陶焕(13294175866)
	 * @throws BaseException 
	 */
	public CommonResult<T> checkEmptyFields(Object[] field,String errorMsg[]) throws BaseException{
		log.info("AbstractGenericServiceImpl.checkEmptyField请求参数:{},{}", field,errorMsg);
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		if(CollectionUtil.isNotEmpty(field)){
			for(int i = 0; i < field.length; i++){
				result = checkEmptyField(field[i], errorMsg[i]);
				if(result.getSuccess() != CommonResult.successCode){
					log.info("AbstractGenericServiceImpl.checkEmptyField返回参数:{}", result);
					throw new BaseException(result.getMessage());
					//return result;
				}
			}
		}
		//成功
		result.setSuccess(CommonResult.successCode);
		log.info("AbstractGenericServiceImpl.checkEmptyField返回参数:{}", result);
		return result;
	}
	
	/**
	 * 
	 * <p>校验字段是否唯一(批量)</p>
	 * @param model
	 * @param isInsert
	 * @return
	 * @author 陶焕(13294175866)
	 * @throws Exception 
	 */
	public CommonResult<T> checkUniqueFields(boolean isInsert,String id,String[] errorMsg,String[][] fieldNames,
			Object[][] fieldValue) throws Exception{
		log.info("AbstractGenericServiceImpl.checkUniqueField请求参数:{},{},{},{}", isInsert,id,errorMsg,fieldNames,fieldValue);
		CommonResult<T> result = new CommonResult<T>(CommonResult.failureCode);
		if(CollectionUtil.isNotEmpty(fieldNames)){
			for(int i = 0; i < fieldNames.length; i++){
				result = checkUniqueField(isInsert, id, errorMsg[i], fieldNames[i], fieldValue[i]);
				if(result.getSuccess() != CommonResult.successCode){
					log.info("AbstractGenericServiceImpl.checkUniqueField返回参数:{}", result);
					throw new BaseException(result.getMessage());
					//return result;
				}
			}
		}
		//确定是唯一
		result.setSuccess(CommonResult.successCode);
		log.info("AbstractGenericServiceImpl.checkUniqueField返回参数:{}", result);
		return result;
	}
	
	/**
	 * 
	 * <p>用于将时间列添加到搜索条件中</p>
	 * @param condition 搜索条件
	 * @param pageParam 参数
	 * @return
	 * @author 陶焕(13294175866)
	 */
	protected DetachedCriteria addDateColumn(DetachedCriteria condition,PageParamCommand pageParam){
		//处理时间
		if(Validator.isNotEmpty(condition)&&Validator.isNotEmpty(pageParam)){
			String dateColumn = pageParam.getDateColumn();
			if(StrUtil.isNotBlank(dateColumn)){
				Date startDate = pageParam.getStartDate();
				Date endDate = pageParam.getEndDate();
				//时间大小判断
				if(!Validator.isEmpty(startDate)&&!Validator.isEmpty(endDate)){
					if(startDate.getTime() > endDate.getTime()){
						Date tmpDate = startDate;
						startDate = endDate;
						endDate = tmpDate;
					}
				}
				if(!Validator.isEmpty(startDate)){
					//大于等于比较小的时间
					condition.add(Restrictions.ge(dateColumn, startDate));
				}
				if(!Validator.isEmpty(endDate)){
					//小于等于比较大的时间
					condition.add(Restrictions.le(dateColumn, endDate));
				}
				
			}
		}
		return condition;
	}
	
	
	@Override
	public CommonResult<Integer> updateBySql(String updateString, Object... params) throws Exception {
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		int data = getDao().updateBySql(updateString, params);
		result.setData(data);
		result.setSuccess(CommonResult.successCode);
		return result;
	}

	@Override
	public CommonResult<Integer> updateBySql(String updateString, String[] paramNames, Object... params) throws Exception {
		CommonResult<Integer> result = new CommonResult<Integer>(CommonResult.failureCode);
		int data = getDao().updateBySql(updateString, paramNames, params);
		result.setData(data);
		result.setSuccess(CommonResult.successCode);
		return result;
	}
	
}
